#include <dretve.h>
#include <ispis.h>
#include <vrijeme.h>

#define BROJAC 100000000000ULL //"beskonacno"
#define MJERENJE_TRAJE	2 //samo potencije od 2! (nema 64-bitnog djeljenja!)

volatile static unsigned long long brojac = BROJAC;//long long
volatile static unsigned int kraj = 0;

static void broji(int v, char ime, char dio)
{
	unsigned long long k = 0;
	int j;
	for (j = 1; j <= v && !kraj; j++) {
		ispisi("Dretva %c :: dio %c (%d/%d)\n", ime, dio, j, v);

		for (k = 0; k < brojac && !kraj; k++)
			asm volatile ("":::"memory");
	}

	if (kraj) { /* mjerim */
		brojac = k / MJERENJE_TRAJE;//djeljenje s potencijama od 2!
		ispisi("1 s = %d iter\n", brojac);
		kraj = 0;
	}
}

static void dretva_koja_broji(void *param)
{
	broji(MJERENJE_TRAJE, 'G', 'A');
}

static void alarm (void *param)
{
	kraj = 1;
}

struct pd {
	int a_dio, b_dio, c_dio, d_dio; //trajanje pojedinih elemenata u sek.
	int *mon_az, *mon_bz, *mon_cz, *mon_dz;
	int *mon_ao, *mon_bo, *mon_co, *mon_do;
	int pocetna_odgoda;
	int prio;
	char ime;
};

void dio (int trajanje, int *monz, int *mono, char ime, char dio)
{
	if (monz != NULL)
		zakljucaj(*monz);

	broji(trajanje, ime, dio);

	if (mono != NULL)
		otkljucaj(*mono);
}

static void dretva(void *param)
{
	struct pd *p = param;
	int id = id_dretve();
	vrijeme_t koliko;

	postavi_prioritet(p->prio);
	koliko.nsekunde = 0;
	koliko.sekunde = p->pocetna_odgoda;
	odgodi(koliko);

	ispisi("Dretva %c pocela (id=%d, prio=%d)\n", p->ime, id, p->prio);

	dio(p->a_dio, p->mon_az, p->mon_ao, p->ime, 'A');
	dio(p->b_dio, p->mon_bz, p->mon_bo, p->ime, 'B');
	dio(p->c_dio, p->mon_cz, p->mon_co, p->ime, 'C');
	dio(p->d_dio, p->mon_dz, p->mon_do, p->ime, 'D');
}

void test_nas_prio()
{
	ispisi("\n[%s:%s:%d]\n", __FILE__, __FUNCTION__, __LINE__);

	int mon1, mon2;
	vrijeme_t koliko;
	int a, i;
	int dr[5];
	struct pd params[5] = {
		{	3,9,0,3,
			NULL, &mon1, NULL, NULL,
			NULL, &mon1, NULL, NULL,
			0, 50, 'A'
		},
		{	3,0,0,3,
			NULL, NULL, NULL, NULL,
			NULL, NULL, NULL, NULL,
			6, 40, 'B'
		},
		{	3,3,3,3,
			NULL, &mon2, &mon1, NULL,
			NULL, NULL, &mon2, &mon1,
			9, 30, 'C'
		},
		{	3,0,0,3,
			NULL, NULL, NULL, NULL,
			NULL, NULL, NULL, NULL,
			18, 20, 'D'
		},
		{	3,3,0,3,
			NULL, &mon2, NULL, NULL,
			NULL, &mon2, NULL, NULL,
			21, 10, 'E'
		}
	};

	koliko.sekunde = MJERENJE_TRAJE;
	koliko.nsekunde = 0;
	//postavlja se alarm koji ce opalit nakon sekunde s prioritetom ove
	//dretve!
	a = postavi_alarm_pr(0, koliko, alarm, NULL, STVORINOVI);

	//alarm ce se obradit u novoj dretvi - stvori novu dretvu manjeg
	//prioriteta koja ce vrtit petlju - inace ju alarm ne bi prekinuo!
	dr[0] = stvori_dretvu(dretva_koja_broji, NULL);
	cekaj_kraj_dretve(dr[0]);

	obrisi_alarm(a);

	mon1 = dohvati_sinkro(MONITOR, 0, REKURZ | NASPRIO, 0);
	mon2 = dohvati_sinkro(MONITOR, 0, REKURZ | NASPRIO, 0);
	if (mon1 == -1 || mon2 == -1) {
		ispisi("nema monitora!\n");
		return;
	}
	
	for (i = 0; i < 5; i++)
		dr[i] = stvori_dretvu(dretva, &params[i]);


	for (i = 0; i < 5; i++)
		cekaj_kraj_dretve(dr[i]);
	
	obrisi_sinkro(mon1);
	obrisi_sinkro(mon2);
}
